﻿/**
 * Copyright (C) 2012 original author and authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace NGuice.Inject.Internal.Util
{
    /// <summary>
    /// 使用Interlocked进行原子操作的数组对象,此类从java中的AtomicReferenceArray移植而来
    /// </summary>
    [Serializable]
    public class AtomicReferenceArray<E>
        where E: class
    {
        private readonly E[] array; // must have exact type Object[]

        public AtomicReferenceArray(int length) {
            array = new E[length];
        }

        public AtomicReferenceArray(E[] array) {
            // Visibility guaranteed by final field guarantees
            array = new E[array.Length];
            System.Array.Copy(array, this.array, array.Length);
            //this.array = Arrays.copyOf(array, array.length, Object[].class);
        }

        public  int Length {
            get
            {
                return array.Length;
            }
        }

        public E this[int i] {
            get
            {
                return GetAndSet(i, array[i]);
            }

            set
            {
                Interlocked.Exchange<E>(ref array[i], value);
            }
        }

        /// <summary>
        /// 设置新值并返回旧值(当前值没有改变，则替换新值并返回旧值）
        /// </summary>
        /// <param name="i"></param>
        /// <param name="newValue"></param>
        /// <returns></returns>
        public E GetAndSet(int i, E newValue) {
            E current = array[i];
            return Interlocked.CompareExchange<E>(ref array[i], newValue, current);
        }

        /// <summary>
        /// 如果实际的值与期望的值相等，则使用update替换，并返回true。否则返回false
        /// </summary>
        /// <param name="i"></param>
        /// <param name="expect"></param>
        /// <param name="update"></param>
        /// <returns></returns>
        public bool CompareAndSet(int i, E expect, E update) {
            return Interlocked.CompareExchange(ref array[i], update, expect).Equals(expect);
        }

        public override string ToString()
        {
            int iMax = array.Length - 1;
            if (iMax == -1)
                return "[]";

            StringBuilder b = new StringBuilder();
            b.Append('[');
            for (int i = 0; ; i++)
            {
                b.Append(this[i]);
                if (i == iMax)
                    return b.Append(']').ToString();
                b.Append(',').Append(' ');
            }
        }
    }
}
